import json
from decimal import Decimal

from django.http import JsonResponse, HttpResponseBadRequest
from django.shortcuts import render

# Create your views here.
from django.utils import timezone
from django.views import View
from django_redis import get_redis_connection

from apps.goods.models import SKU
from apps.orders.models import OrderInfo, OrderGoods
from apps.users.models import Address
from utils.viewmixin import LoginMixin


class OrdersSettlementView(LoginMixin, View):
    """结算订单"""

    def get(self, request):
        """提供订单结算界面"""
        # 获取登录用户
        user = request.user

        # 查询当前用户的所有地址信息
        addresses = Address.objects.filter(user=request.user, is_deleted=False)

        # 从redis购物车中查询出被勾选的商品信息
        redis_conn = get_redis_connection('carts')
        redis_cart = redis_conn.hgetall('cart_%s' % user.id)
        cart_selected = redis_conn.smembers('selected_%s' % user.id)
        cart = {}
        for sku_id in cart_selected:
            cart[int(sku_id)] = int(redis_cart[sku_id])

        # 查询商品信息
        sku_list = []

        # 显示商品信息
        skus = SKU.objects.filter(id__in=cart.keys())
        for sku in skus:
            sku_list.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'count': cart[sku.id],
                'price': sku.price
            })

        # 补充运费
        freight = Decimal('10.00')

        addresses_list = []
        for address in addresses:
            addresses_list.append({
                'id': address.id,
                'province': address.province.name,
                'city': address.city.name,
                'district': address.district.name,
                'place': address.place,
                'receiver': address.receiver,
                'mobile': address.mobile
            })

        # 渲染界面
        context = {
            'addresses': addresses_list,
            'skus': sku_list,
            'freight': freight,
        }
        return JsonResponse({"code": 0, "errmsg": 'ok', "context": context})


class OrderCommitView(LoginMixin, View):
    """订单提交"""
    def post(self, request):
        """保存订单信息和订单商品信息"""
        # 1.获取用户对象user和address_id pay_method
        user = request.user
        json_data = json.loads(request.body)
        address_id = json_data.get("address_id")
        pay_method = json_data.get("pay_method")

        # 2.校验数据
        # 校验参数
        if not all([address_id, pay_method]):
            return HttpResponseBadRequest('缺少必传参数')

        # 判断address_id是否合法
        try:
            address = Address.objects.get(id=address_id)
        except Exception:
            return HttpResponseBadRequest('参数address_id错误')

        # 判断pay_method是否合法
        if pay_method not in {OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']}:
            return HttpResponseBadRequest('参数pay_method错误')

        # 3.把数据保存到数据库
        # 3.1
        # 保存订单数据， order_info
        # 生成订单号，年月日时分秒+用户编号 %f微秒 %09d表示9位数，左侧不够补0
        order_id = timezone.localtime().strftime('%Y%m%d%H%M%S%f') + ('%09d' % user.id)

        # 总数量计算，临时，赋值0
        total_count = 0

        # 总金额计算，临时，赋值0
        total_amount = 0
        freight = Decimal('10.00')

        # 根据pay_method来悬着一个订单状态status
        # 如果是支付宝，那么状态就是待付款，否则就是待发货
        status = OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else \
            OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        from  django.db import  transaction
        with transaction.atomic():  # 开启事务
            save_id = transaction.savepoint()
            try:
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address_id=address_id,
                    total_count=total_count,
                    total_amount=total_amount,
                    freight=freight,
                    pay_method=pay_method,
                    status=status,
                )

                print(order)
            except Exception as e:
                print(e)
                return HttpResponseBadRequest('订单保存失败')

            # 3.2 保存订单的商品数据 order_goods
            # 连接redis
            redis_conn = get_redis_connection('carts')
            # 获取hash{sku_id:count}
            carts_dict = redis_conn.hgetall("cart_%s" % user.id)

            # 获取set
            selected_list = redis_conn.smembers('selected_%s' % user.id)
            new_cart_dict = {}

            # 遍历所有选中的id列表
            for sku_id in selected_list:
                # 把数据存到新的字典new_cart_dict，并且转为int
                count = carts_dict[sku_id]
                new_cart_dict[int(sku_id)] = int(count)

            try:
                # new_cart_dict 是所有选中的商品的id和数量，并且是转为int后的
                skus = SKU.objects.filter(id__in=new_cart_dict.keys())
            except Exception as e:
                print(e)
                return JsonResponse({'code': 400, 'errmsg': '数据查询失败'})

            try:
                # 遍历skus 生成每个sku的订单商品数据  order_goods对象
                for sku in skus:
                    # 判断库存是否够  count:3  stock(库存)：1   count <= stock
                    count = new_cart_dict[sku.id]
                    print(sku.id, sku.stock)
                    if count > sku.stock:
                        return JsonResponse({'code': 400, 'errmsg': '库存不足'})

                    # 如果库存够 stock -= count   销量 sales += count
                    sku.stock -= count
                    sku.sales += count
                    sku.save()

                    OrderGoods.objects.create(
                        order_id=order_id,
                        sku=sku,
                        count=count,
                        price=sku.price
                    )

                    # 计算订单  总数量计算和金额计算
                    # 把单个商品的数量累加到订单的总数量里
                    order.total_count += count
                    # 把单个商品的总价累加到订单的总价里
                    order.total_amount += count * sku.price

                # 总价，加上运费
                order.total_amount += order.freight
                # 保存对象
                order.save()
                print('保存成功')
            except Exception as e:
                print(e)
                # 回滚到保存点
                transaction.savepoint_rollback(save_id)
                return HttpResponseBadRequest('订单保存失败')

            # 提交从保存点到当前状态的所有数据库事务操作
            transaction.savepoint_commit(save_id)
        # 把redis里购物车选中的商品信息移除
        redis_conn.hdel('cart_%s' % user.id, *selected_list)
        redis_conn.srem('selected_%s' % user.id, *selected_list)
        # 4.返回响应
        return JsonResponse({'code': 0, 'errmsg': '下单成功', 'order_id': order.order_id})
